
// FIXME - why is every event launched twice?


// --- data & fragment ---------------------------------------------------------

dcat_instance.oninit(function(Y) {

  Cat.fragments = {}
  Cat.fragment = {}

  Cat.fragment.focused = null;
  Cat.fragment.highest_z = 500;

  Cat.Fragment = function(el, state) {
    this.type = 'Fragment';
    this.setState(state);
    this.setElement(el);
    this.setupUI();
    console.log('will subscribe');
    this.subscribe();
  }

  Y.augment(Cat.Fragment, Y.Event.Target);

  Cat.Fragment.prototype.cry = function(message) {
    console.log(this.type+' cries: '+message);
  }

  Cat.Fragment.prototype.setElement = function(el) {
    this.el = el;
    if (el.id) {
      this.el_id = el.id;
    } else {
      this.cry('my element has no id');
    }
    this.el.cat_fragment = this;
    this.parent = this.node().ancestor('.Fragment');
    if (this.parent) {
      var f = this.parent.get('cat_fragment');
      if (f && f.afterAppendChild) {
        f.afterAppendChild(this, this.el);
      }
    }
  }

  Cat.Fragment.prototype.setState = function(state) {
    this.state = state;
  }

  Cat.Fragment.prototype.getState = function() {
    return [this.state, this.geChildrenState()];
  }

  Cat.Fragment.prototype.subscribe = function() {
    console.log('my state', this.state);
    this.node().on('mousedown', this.onMouseDown, this);
    console.log('my state', this.state);
    this.setDraggable(this.state.draggable);
  }

  Cat.Fragment.prototype.setupUI = function() {
    if (!this.el) {
      if (this.el_id) {
        var el = document.getElementById(this.el_id);
        if (el) {
          return this.el = el;
        } else {
          this.cry('Could not found element '+this.el_id+' :(');
          return null;
        }
      }
      return null;
      this.cry('no element or element id:(');
    }
  }

  Cat.Fragment.prototype.getEl = function() {
    if (!this.el) {
      this.setupUI();
    }
    return this.el;
  }

  Cat.Fragment.prototype.node = function() {
    if (!this._node) {
      this._node = Y.get(this.getEl());
      this.setupUI();
    }
    return this._node;
  }



  Cat.Fragment.paste = function(what) {
    var append;
    console.log('focused is', Cat.fragment.focused);
    if (Cat.fragment.focused) {
      if (what.node) {
        append = what.node();
      } else {
        append = what;
      }
      console.log(Cat.fragment.focused);
      var paste_into = Cat.fragment.focused;
      while (paste_into && !paste_into.paste) {
        console.log('paste_into has no paste', paste_into);
        paste_into = paste_into.parent;
      }
      if (paste_into && paste_into.paste) {
        paste_into.paste(append);
        return;
      }
    }
    Y.get('.desktopContainer').appendChild(append);
  }

  Cat.Fragment.prototype.geChildrenState = function() {
    var state = [];
    var children = this.getChildren();
    for (ch in children) {
      var child = children[ch];
      if (child.getState) {
        state.push(child.getState());
      }
    }
    return state;
  }

  Cat.Fragment.prototype.getChildren = function() {
    return [];
  }

  Cat.Fragment.prototype.fragmentsOf = function(nodes) {
    if (typeof(nodes) == 'undefined') { throw "first argument should be an array, was "+nodes }
    if (nodes.length == 0) {
      console.log('no children to select fragments from');
      return [];
    }
    var f, fragments = [];
    nodes.each(function(n) {
      console.log('node is ', this);
      if (this.get && (f = n.get('cat_fragment'))) {
        console.log('fragment is ', f);
        fragments.push(f);
      }
    });
    console.log('fragments are', fragments);
    return fragments;
  }

  Cat.Fragment.prototype.setDraggable = function(bool) {
    console.log('setDraggable', this, bool);
    this.is_draggable = bool;
    if (bool === true && !this.draggable) {
      this.draggable = window.dcat_instance.draggable('#'+this.el.id);
    }
  }

  Cat.Fragment.prototype.focus = function() {
    if (Cat.fragment.focused == this) { return; }
    if (Cat.fragment.focused) {
      Cat.fragment.focused.blur();
    }
    Cat.fragment.focused = this;
    this.node().addClass('focusedFragment');
    this.bringToFront();
  }

  Cat.Fragment.prototype.bringToFront = function() {
    Cat.fragment.highest_z += 1;
    this.node().setStyle('zIndex', Cat.fragment.highest_z);
  }

  Cat.Fragment.prototype.blur = function() {
    this.node().removeClass('focusedFragment');
  }

  Cat.Fragment.prototype.close = function() {
    var node = this.node();
    var parent = node.get('parentNode');
    /* sometimes we subscribe more than once to this event,
     *  so after first call there is no parrent
     */
    if (parent) {
      node.get('parentNode').removeChild(node);
    }
  }

  Cat.Fragment.prototype.onMouseDown = function(e) {
    if (this.node() == e.target) {
      this.focus();
      e.stopPropagation();
    }
  }




  // --- Container -------------------------------------------------------------

  Cat.fragment.Document = function(el, o) {
    Cat.fragment.Document.superclass.constructor.call(this, el, o);
    this.type = 'Document';
    //this.focus();
  }

  Y.extend(Cat.fragment.Document, Cat.Fragment);

  Cat.fragment.Document.prototype.getChildren = function() {
    return this.fragmentsOf(this.node().get('children'));
  }

  Cat.fragment.Document.prototype.subscribe = function() {
    Cat.fragment.Document.superclass.subscribe.call(this);
    var layout = new Cat.layout.Vertical(this.el);

    /* reject pages in this container */
    layout.subscribe('layout:appendChild', function(ev) {
      if (this.state.droppable === false) {
        //return false;
      }
      console.log('layout:appendChild', ev);
      var node = Y.get(ev[0]);
      var f = node.get('cat_fragment');
      if (f && f.type == 'Page') {
        return false;
      }
      return true;
    }, this);
  }





  // --- Page ------------------------------------------------------------------


  Cat.Page = function(el, o) {
    Cat.Page.superclass.constructor.call(this, el, o);
    this.type = 'Page';
    this.children = [];
    //this.focus();
  }

  Cat.Page.focused_page = null;
  Cat.Page.highest_z = 500;

  Y.extend(Cat.Page, Cat.Fragment);

  Cat.Page.prototype.getState = function() {
    this.state.name = this.node().query('.pageTitle').get('cat_fragment').getData();
    return Cat.Page.superclass.getState.call(this);
  }

  Cat.Page.prototype.getChildren = function() {
    this.node();
    console.log('children are ', this.container.get('children'));
    console.log('fragments are', this.fragmentsOf(this.container.get('children')));
    return this.fragmentsOf(this.container.get('children'));
  }

  Cat.Page.prototype.paste = function(node) {
    this.node();
    this.container.appendChild(node);
  }

  Cat.Page.prototype.subscribe = function() {    
    var layout = new Cat.layout.Vertical(this.container);

    layout.subscribe('layout:appendChild', function(ev) {
      console.log('layout:appendChild', ev);
      var node = Y.get(ev[0]);
      var f = node.get('cat_fragment');
      if (f && f.type == 'Page') {
        return false;
      }
      return true;
    }, this);
/*
    this.container.on('mousedown', function() {
      console.log('container mouse down', Cat.Field.focused);
      if (Cat.Field.focused && Cat.Field.focused.blur) {
        Cat.Field.focused.blurWindow();
      }
    }, this);
*/
    this.node().on('mousedown', this.onMouseDown, this);

    this.node().query('.head .deleteWindow').on('click', this.onDeleteClick, this);
    this.node().query('.head .saveWindow').on('click', this.save, this);
    this.node().query('.head .closeWindow').on('click', this.onCloseButtonClick, this);
  }

  Cat.Page.prototype.setupUI = function() {
    console.log('setupUI');
    Cat.Page.superclass.setupUI.call(this);
    this.container = this.node().query('.pageContainer');
  }
  

  Cat.Page.prototype.save = function() {
    var state = this.getState();
    console.log(state);
    // send to server
    json_state = Y.JSON.stringify(state)
    console.log(json_state);
    Y.io('/callback/cms-desktop/save', {
      data : 'state='+json_state,
      method: 'POST',
      on : {
        complete : function(id, o, args) {
          console.log(o);
          eval(o.responseText);
        }
      }
    });
  }

  Cat.Page.prototype.onMouseDown = function(e) {
    if (Y.get(e.target) != this.closeButton) {
      this.focus(e);
    }
  }

  Cat.Page.prototype.onDeleteClick = function(e) {
    this.deletePage();
  }

  Cat.Page.prototype.deletePage = function() {
    Y.io('/callback/cms-desktop/delete', {
      data : 'uuid='+this.state.uuid,
      method: 'POST',
      context: this,
      on : {
        complete : function(id, o, args) {
          console.log(o);
          if (o.responseText == 'OK') {
            this.close();
          }
        }
      }
    });
  }

  Cat.Page.prototype.focus = function() {
    Cat.Page.superclass.focus.call(this);
    this.focusWindow();
    //this.node().setStyle('zIndex', Cat.Page.highest_z += 1);
  }

  Cat.Page.prototype.focusWindow = function() {
    this.node().addClass('focusedPage');
  }

  Cat.Page.prototype.blur = function() {
    Cat.Page.superclass.blur.call(this);
    this.blurWindow();
  }

  Cat.Page.prototype.blurWindow = function() {
    this.node().removeClass('focusedPage');
  }


  Cat.Page.prototype.onCloseButtonClick = function(e) {
    this.close();
  }

  Cat.Page.prototype.close = function() {
    var node = this.node();
    var parent = node.get('parentNode');
    /* sometimes we subscribe more than once to this event,
     *  so after first call there is no parrent
     */
    if (parent) {
      node.get('parentNode').removeChild(node);
    }
  }


// --- Field -------------------------------------------------------------------

  Cat.Field = function(el, o) {
    Cat.Field.superclass.constructor.call(this, el, o);
    this.showing = 'static';
    this.setShowingState('showing');
    this.type = "Field";
  }

  Y.extend(Cat.Field, Cat.Fragment);

  Cat.Field.focused = null;

  Cat.Field.prototype.setupUI = function() {
    Cat.Field.superclass.setupUI.call(this);
    this.static_el = this.node().query('.f-static');
    this.editable_el = this.node().query('.f-editable');
    console.log('elements', this.static_el, this.editable_el);
  }

  Cat.Field.prototype.subscribe = function() {
    this.static_el.on('click', this.showEditable, this);
    this.editable_el.on('blur', this.onBlur, this);
    this.editable_el.on('keydown', function(ev) {
      if (ev.charCode == 27) { this.onBlur() }
    }, this);
    this.setData(this.state.data);
  }

  Cat.Field.prototype.setData = function(data) {
    //console.log('set data', data);
    this.state.data = data;
    this.setStaticData(data);
    this.setEditableData(data);
  }

  Cat.Field.prototype.getData = function() {
    this.setupUI();
    return this.state.data;
  }
  
  Cat.Field.prototype.setDraggable = function(bool) {
    var old_draggable = this.draggable;
    Cat.Field.superclass.setDraggable.call(this, bool);
    if (old_draggable != this.draggable) {
        this.draggable.on('drag:mouseDown', function(ev) {
          console.log('drag:mousedown');
          this.focus();
          var page = this.node().ancestor('.Page');
          if (page) {
            page.get('cat_fragment').focus();
            if (this.is_draggable && this.showing != 'static') {
              // sometimes the fragment would pop out
              ev.halt();
            }
          }
      }, this);
    }
  }

  Cat.Field.prototype.setShowingState = function(className) {
    this.node().removeClass(this.showingState);
    this.showingState = className;
    this.node().addClass(className);
  }
  
  Cat.Field.prototype.showEditable = function(ev) {
    console.log('showEditable Fragment');
    if (!this.static_el) {
      console.log('lost my element!');
      this.setupUI();
    }
    this.showing = 'editable';
    this.setShowingState('editing');
    console.log('field focused', this);
    Cat.Field.focused = this;
    /*
    this.static_el.setStyle('display', 'none');
    this.editable_el.setStyle('display', 'block');
    */
    this.editable_el.focus();
    if (typeof(ev) != 'undefined') {
      ev.stopPropagation();
    }
  }

  Cat.Field.prototype.showStatic = function(ev) {
    //this.editable_el.setStyle('display', 'none');
    this.showing = 'static';
    this.setShowingState('showing');

    this.setData(this.getEditableData());
    //this.static_el.setStyle('display', 'block');
    if (typeof(ev) != 'undefined') {
      ev.stopPropagation();
    }
  }
  
  Cat.Field.prototype.getEditableData = function() {    
    return this.editable_el.get('value');
    //console.log('implement getEditableData');
  }

  Cat.Field.prototype.setEditableData = function(data) {
    this.editable_el.set('value', data);
    //console.log('implement setEditableData');
  }

  Cat.Field.prototype.getStaticData = function() {
    return this.static_el.get('innerHTML');
    //console.log('implement getStaticData');
  }

  Cat.Field.prototype.setStaticData = function(data) {
    this.static_el.set('innerHTML', data);
    //console.log('implement setStaticData');
  }

  Cat.Field.prototype.onBlur = function() {
    this.blur();
  }

  Cat.Field.prototype.blur = function() {
    Cat.Field.superclass.blur.call(this);
    console.log('blur', this);
    //Cat.Field.focused = null;
    this.showStatic();
  }


  // --- InputField fragment ---

  Cat.fragments.InputField = function(el, o) {
    Cat.fragments.InputField.superclass.constructor.call(this, el, o);
    this.type = "InputField";
  }

  Y.extend(Cat.fragments.InputField, Cat.Field);



  Cat.fragments.InputText = function(el, o) {
    Cat.fragments.InputText.superclass.constructor.call(this, el, o);
    this.type = "InputText";
  }
  
  Y.extend(Cat.fragments.InputText, Cat.Field);

  Cat.fragments.InputText.prototype.showEditable = function(ev) {
    this.node();
    var size = this.static_el.get('clientWidth');
    console.log('size', size);
    Cat.fragments.InputText.superclass.showEditable.call(this, ev);
    if (size > 0) {
      this.editable_el.setStyle('width', (size)+'px');
    }
  }

  Cat.fragments.InputText.prototype.setupUI = function() {
    Cat.fragments.InputText.superclass.setupUI.call(this);
    this.editable_el.on('keydown', function(ev) {
      if (ev.charCode == 10 || ev.charCode == 13) { this.onBlur() }
    }, this);
  }




  Cat.fragments.TextField = function(el, o) {
    Cat.fragments.TextField.superclass.constructor.call(this, el, o);
    this.type = "TextField";
  }

  Y.extend(Cat.fragments.TextField, Cat.Field);

  Cat.fragments.TextField.prototype.showEditable = function(ev) {
    console.log('showEditable', this);
    this.node();
    var height = this.static_el.get('clientHeight');
    if (height > 0) {
      this.editable_el.setStyle('height', height+'px');
    }
    Cat.fragments.TextField.superclass.showEditable.call(this, ev);    
  }

  Cat.fragments.TextField.prototype.getEditableData = function() {
    var data = Cat.fragments.TextField.superclass.getEditableData.call(this);
    return data.split("\n").join("<br />");
  }

  Cat.fragments.TextField.prototype.setEditableData = function(data) {
    this.editable_el.set('value', data.split("<br />").join("\n"))
  }


});
